package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.Dictionary;
import flash.events.KeyboardEvent;
import flash.display.*;
import flash.geom.Rectangle;
import flash.geom.*;
import flash.text.TextField;
import flash.text.TextFormat;

public class TheCanvas extends MovieClip
{
	//canvas settings
	private var distance:Number;
	private var w:Number;
	private var h:Number;
	public var params:Object;

 	public var border:Boolean;
	public var cornerR:Number=10;
	
	//private variables
	private var pen:Graphics;
	private var grid_pen:Graphics;
	private var grid:Sprite;
	public var responsible:Tool;
	private var hash:Dictionary;
	private var closePointDistance:Number=15;
	private var closeLineDistance:Number=15;
	//data variables
	private var xml:XML; //loaded xml
	
	//collections
	private var items:Array;
	public var data:Array=[];
	public var path_mc:Sprite;
	public var mouse_mc:Sprite;
	public var point_mc:Sprite;
	public var mesh_mc:Sprite;
	public var text_mc:Sprite;
	
	public var point_pen:Graphics;
	public var path_pen:Graphics;

	public var tools:Collection;
	
	public var viewTool:Tool;
	private var move_tool:Tool;
	private var drawLineTool:Tool;
	private var deleteTool:Tool;
	private var colorTool:Tool;
	private var cornerTool:Tool;
	private var holeTool:Tool;
	private var arcTool:Tool;
	private var rectTool:Tool;
	private var hingeTool:Tool;
	private var rulerTool:Tool;
	private var textTool:Tool;
	
	public var selection:Selection;
	//control: 17, 83
	private var preciseKey:Boolean;
	
	private var _draw:Draw;
	private var panel:MovieClip;

	private var text_data:Dictionary;
	
	PointObj;
	Hole;
	Holes;
	Ruler;
	Rulers;
	Mesh;
	Path;
	Text;
	Texts;
	ColorFills;
	ColorFill;
	Arcs;
	Arc;
	Rect;
	Rectangles;
	Hinge;
	Hinges;
	
	
	//tools key:
	//r: move tool
	//e: draw line tool
	//d: delete tool
	//v: view tool
	//w: curve tool
	//a: arc tool
	//o: hole tool
	//c: color tool
	//r: rect tool
	//h: hinger tool
	//l: ruler tool
	//t: text tool
	
	public function TheCanvas(w:Number=500,h:Number=500,dist:Number=20,params:Object=null)
	{
		super();
		this.params=params;
		tools=new Collection();
		selection=new Selection();
		text_data=new Dictionary(true);
		
		//add tools here
		move_tool=new MoveTool();
		drawLineTool=new DrawLineTool();
		viewTool=new ViewTool();
		deleteTool=new DeleteTool();
		colorTool=new ColorTool();
		cornerTool=new CornerTool();
		holeTool=new HoleTool();
		arcTool=new ArcTool();
		rectTool=new RectTool();
		hingeTool=new HingeTool();
		rulerTool=new RulerTool();
		textTool=new TextTool();

		tools.addItem(move_tool);
		tools.addItem(drawLineTool);
		tools.addItem(viewTool);//v
		tools.addItem(deleteTool);//d
		tools.addItem(colorTool);//c
		tools.addItem(cornerTool);//w
		tools.addItem(holeTool);//o
		tools.addItem(arcTool);//a
		tools.addItem(rectTool);//t
		tools.addItem(hingeTool);//h
		tools.addItem(rulerTool);//l
		tools.addItem(textTool);//t
		
		
		this.distance=dist;
		this.w=w;
		this.h=h;
		this.pen=this.graphics;
		hash=new Dictionary();
		

		_draw=new Draw(this);
		
		//grid layer
		grid=_draw.getNewLayer();
		grid_pen=_draw.getPen(grid);
		
		//path layer
		path_mc=_draw.getNewLayer();
		path_pen=_draw.getPen(path_mc);
		
		point_mc=_draw.getNewLayer();
		point_pen=_draw.getPen(point_mc);
		
		//mesh layer
		mesh_mc=_draw.getNewLayer(false);
		
		//mouse layer
		mouse_mc=_draw.getNewLayer();

		//text layer
		text_mc=_draw.getNewLayer();

		
		
		if(params.xml_url!=undefined){
			loadxml(params.xml_url.toString());
		}else{
			loadxml("canvas.xml");
		}

		panel=new Panel();
		setPanelEvent();
	}

	public function setPanelEvent():void{
		panel.move_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.view_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.line_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.curve_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.arc_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.hole_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.hinge_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.rect_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.text_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.ruler_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.load_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);
		panel.save_tool_btn.addEventListener(MouseEvent.CLICK,toolClickHandler);

		panel.move_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.view_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.line_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.curve_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.arc_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.hole_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.hinge_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.rect_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.text_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.ruler_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.load_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);
		panel.save_tool_btn.addEventListener(MouseEvent.MOUSE_DOWN,blankHandler);

		panel.move_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.view_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.line_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.curve_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.arc_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.hole_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.hinge_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.rect_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.text_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.ruler_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.load_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		panel.save_tool_btn.addEventListener(MouseEvent.MOUSE_UP,blankHandler);
		
	}

	public function blankHandler(evt:MouseEvent):void{
		evt.stopImmediatePropagation();
	}
	
	public function toolClickHandler(evt:MouseEvent):void{
		var target:Object=evt.currentTarget;
		switch(target){
			case panel.move_tool_btn:
			move_tool.responsible(this);
			break;
			case panel.view_tool_btn:
			viewTool.responsible(this);
			break;
			case panel.line_tool_btn:
			drawLineTool.responsible(this);
			break;
			case panel.curve_tool_btn:
			cornerTool.responsible(this);
			break;
			case panel.arc_tool_btn:
			arcTool.responsible(this);
			break;
			case panel.hole_tool_btn:
			holeTool.responsible(this);
			break;
			case panel.hinge_tool_btn:
			hingeTool.responsible(this);
			break;
			case panel.rect_tool_btn:
			rectTool.responsible(this);
			break;
			case panel.text_tool_btn:
			textTool.responsible(this);
			break;
			case panel.ruler_tool_btn:
			rulerTool.responsible(this);
			break;
			case panel.load_tool_btn:
			break;
			case panel.save_tool_btn:
			break;
			
		}
		evt.stopImmediatePropagation();
		render();
	}
	
	public function setEvents():void{
		stage.addEventListener(MouseEvent.MOUSE_MOVE,moveHandler);
		stage.addEventListener(MouseEvent.MOUSE_DOWN,downHandler);
		stage.addEventListener(MouseEvent.MOUSE_UP,upHandler);
		stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
		stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
		
	}
	
	public function keyDownHandler(evt:KeyboardEvent):void{
		trace(evt.keyCode);
		var itr:Iterator=new Iterator(tools.toArray());
		
		while(itr.hasNext()){
			var tool:Tool=itr.next() as Tool;
			if(tool.keyCode==evt.keyCode){
				tool.responsible(this);
				render();
				return;
			}
		}
		
		if(evt.keyCode==83){
			preciseKey=true;
			return;
		}
		
		getTool().keyDownHandler(evt);
	}
	
	public function keyUpHandler(evt:KeyboardEvent):void{
		if(evt.keyCode==getTool().keyCode)
		getTool().keyUp();
		
		if(evt.keyCode==83){
			preciseKey=false;
		}
	}
	
	public function upHandler(evt:MouseEvent):void{
		
		getTool().up();
		render();
	}
	
	public function downHandler(evt:MouseEvent):void{
		//someone is always responsible
	
		getTool().down();
		render();
	}
	
	public function moveHandler(evt:MouseEvent):void{
		//someone is always responsible
	
		getTool().move();
		render();
	}
	
	public function renderMouseMC():void{
		getTool().renderMouseMC(mouse_mc);
	}
	
	public function removeChildren(mc:DisplayObjectContainer):void{
		while(mc.numChildren>0){
			mc.removeChildAt(0);
		}
	}
	
	public function pointDistance(p1:Object,p2:Object):Number{
		var dx:Number=p2.x-p1.x;
		var dy:Number=p2.y-p1.y;
		
		return Math.sqrt(dx*dx+dy*dy);
	}
	
	public function simpleMousePoint():Object{
		return {x:mouseX,y:mouseY};
	}
	
	public function getNewId():int{
		return data.length;
	}
	
	public function setSelection(rect:Rectangle):void{
		selection.removeAll();
		var itr:Iterator=new Iterator(points.toArray());
		var item:Object;
		while(itr.hasNext()){
			item=itr.next();
			if(rect.contains(item.x,item.y)){
				addItemToSelection(item);
			}
		}
	}

	public function addItemToSelection(point:Object):void{
		selection.addItem(point);
	}

	public function mousePoint(snap:Boolean=true):Object{
		var x:Number=mouseX;
		var y:Number=mouseY;
		
		if(snap && !preciseKey){
			var tx:Number=Math.round(x/distance)*distance;
			var ty:Number=Math.round(y/distance)*distance;
			
			if(Math.abs(tx-x)<10){
				x=tx;
			}
			if(Math.abs(ty-y)<10){
				y=ty;
			}
		}
		
		return {x:x,y:y};
	}
	
	
	public function loadxml(url:String):void{
		var xml:XML;
		var loader:URLLoader=new URLLoader();
		var url_request:URLRequest=new URLRequest(url);
		
		loader.addEventListener(Event.COMPLETE,init);
		loader.load(url_request);	
	}
	
	public function parseData(xml:XML):void{
		this.xml=xml;
		var name:String;
		var itemName:String;
		var item:*;
		var id:int;
		
		items=[];
		//parse xml and create Collection class for each collection
		for each(var e:XML in xml.children()){
			name=e.name();
			
			//collection
			items[name]=getInstanceOf(name);
			
			for each(var i:XML in e.children()){
				itemName=i.name();
				
				//create item in each collection
				item=getInstanceOf(itemName);
				var atts:XMLList=i.attributes();
				//init item with xml attributes
				for each(var pre:XML in i.@*) {
					item[String(pre.name())]=pre;
					if(pre=="true"){
						item[String(pre.name())]=true;
					}else if(pre=="false"){
						item[String(pre.name())]=false;
					}
				}
				item.text=String(i);
				id=int(i.@id);
				data[id]=item;
				item.canvas=this;
				//add item to collection
				items[name].addItem(item);
			//	trace(name+":"+items[name].getLength());
			}
			
		}
		
		paths.sort();
		points.sort();
		colors.sort();
		
	
	}
	
	//main functions
	
	
	
	//p1 is the join center
	public function getNextPath(p1:Object,p2:Object):void{
		//need to get paths for join point
		var itr:Iterator=new Iterator(getPaths(p1));
		var path:Path;
		while(itr.hasNext()){
			path=itr.next() as Path;
			
		}
		
	}
	
	public function getPath(p1:Object,p2:Object):Path{
		var itr:Iterator=new Iterator(paths.toArray());
		var path:Path;
		
		while(itr.hasNext()){
			path=itr.next() as Path;
			if(path.contains(p1) && path.contains(p2)){
				return path;
			}
		}
		return null;
	}
	
	public function getPaths(point:Object):Array{
		
		var itr:Iterator=new Iterator(paths.toArray());
		var path:Path;
		var result:Array=[];
		
		while(itr.hasNext()){
			path=itr.next() as Path;
			if(path.contains(point)){
				result.push(path);
			}
		}
		return result;
	}
	
	private function draw():void{
		if(items==null)return;
		
		//draw shapes from items
		
		//draw paths
		var itr:Iterator=new Iterator(paths.toArray());
		
		var path:*;
		var id:int;
		path_pen.clear();
		removeChildren(path_mc);
		var from:*;
		var to:*;
		var control:*;
		
		
		var deg:Number;
		var adj:Object;
		var r:Number;
		
		while(itr.hasNext()){
			path=itr.next();
			
			from=data[path.from];
			to=data[path.to];
			
			//this is for portion position
			var three:Array;
			var p1_p:Object;
			var p2_p:Object;
			
			if(to.isRect){
				var rect3:Rect=getRect2(to)
				three=getCorner(to);
				p1_p=data[three[1]];
				p2_p=data[three[2]];
				
				var center2:Object=getPortionOf(p1_p,p2_p,Number(rect3.portion));
				to.x=center2.x;
				to.y=center2.y;
			}else if(to.isHinge){
				/*
				var hinge2:Hinge=getHinge(to);
				three=getCorner(to);
				
				var center3:Object=getPortionOf(p1_p,p2_p,Number(hinge2.portion));
				to.x=center3.x;
				to.y=center3.y;
				*/
				
			}
			
			
			//create new points to make change on it, here need to add to object for new attribute
			from={id:from.id,x:from.x,y:from.y,isCorner:from.isCorner,isArc:from.isArc,isRect:from.isRect,isHinge:from.isHinge};
			to={id:to.id,x:to.x,y:to.y,isCorner:to.isCorner,isArc:to.isArc,isRect:to.isRect,isHinge:to.isHinge};
			r=20;
			//draw for corners shorten
			
			
			if(from.isCorner || from.isArc || from.isRect || from.isHinge){
				if(from.isArc)r=getArc(from).r;
				if(from.isRect)r=getRect2(from).height/2;
				if(from.isHinge)r=getHinge(from).height/2;
				
				deg=getDegree(from,to);
				adj=adjustPoint(from,deg,r);
				from.x=adj.x;
				from.y=adj.y;
			}
			
			if(to.isCorner || to.isArc || to.isRect || to.isHinge){
				if(to.isArc)r=getArc(to).r;
				if(to.isRect)r=getRect2(to).height/2;
				if(to.isHinge)r=getHinge(to).height/2;
				
				deg=getDegree(to,from);
				adj=adjustPoint(to,deg,r);
				to.x=adj.x;
				to.y=adj.y;
			}
			
			if(from!=undefined && to!=undefined){
				
				path_pen.lineStyle(1,0x000000,1);
				path_pen.moveTo(from.x,from.y);
				
				if(path.control==-1){
					path_pen.lineTo(to.x,to.y);
				}else{
					control=data[path.control];
					path_pen.curveTo(control.x,control.y,to.x,to.y);
				}
			}
		}
		
		//draw rect
		
		
		//draw corners
		//loop points
		
		itr=new Iterator(points.toArray());
		var point:Object;
		path_pen.lineStyle(1,0x000000,1);
		while(itr.hasNext()){
			point=itr.next();
			
			var corner:Array;
			var center:Object;
			var p1:Object;
			var p2:Object;
			var pos:int;
			var p1_deg:Number;
			var p2_deg:Number;
			var p1_adj:Object;
			var p2_adj:Object;
			var arc:Arc;
			
			var rect2:Rect;
			var dis:Number;
			var h:Number;
			var hinge:Hinge;
			
			var dx1:Number;
			var dy1:Number;
			
			var p2_rad:Number;
			var h2:Number;
			var deg3:Number;
			
			//texts
			var tf:TextField;
			var txt:Text;
			var tff:TextFormat;
			var obj:Object;
			
			if(point.isCorner){
				
				//is corner
				//get 3 points of the corder with getCorner()
				corner=getCorner(point);
				
				//here is the 3 points
				center=data[corner[0]];
				p1=data[corner[1]];
				p2=data[corner[2]];
				
				pos=-1;
				
				p1_deg=getDegree(center,p1);
				p2_deg=getDegree(center,p2);
				
				p1_adj=adjustPoint(center,p1_deg);
				p2_adj=adjustPoint(center,p2_deg);
				
				//draw curve
				path_pen.moveTo(p1_adj.x,p1_adj.y);
				path_pen.curveTo(center.x,center.y,p2_adj.x,p2_adj.y);
			}else if(point.isText){
				//if point is Text
				tf=text_data[point];

				if(tf!=null){
					if(!selection.contains(point) && tf.text=="" && stage.focus!=tf){
						removePoint(point);
					}

					if(!selection.contains(point)){
						//lost focus
						tf.type="dynamic";
						tf.selectable=false;
						obj=getText(point);
						tf.border=obj.border;
						tf.x=point.x;
						tf.y=point.y;
					}else{
						//get back focus to edit text
						tf.type="input";
						tf.selectable=true;
						tf.border=true;
					}
				}

				if(tf==null){
						tf=new TextField();
						tff=new TextFormat();
						text_data[point]=tf;

						txt=getText(point);
						tff.size=txt.size;

						tf.defaultTextFormat=tff;

						tf.text=txt.content;
						if(tf.text==""){
							tf.text="some text";
						}

						tf.autoSize="left";
					
						tf.x=point.x;
						tf.y=point.y;
						text_mc.addChild(tf);

						
						if(selection.contains(point)){
							tf.border=true;
							tf.type="input";
						}else{
							tf.selectable=false;
							tf.type="dynamic";
						}
				}

			}else if(point.isArc){
				arc=getArc(point);
				//is corner
				//get 3 points of the corder with getCorner()
				corner=getCorner(point);
				
				//here is the 3 points
				center=data[corner[0]];
				p1=data[corner[1]];
				p2=data[corner[2]];
				
				pos=-1;
				
				//degree from point to point
				p1_deg=360-getDegree(center,p1);
				p2_deg=360-getDegree(center,p2);
				
				//p1_deg=arc.from_degree;
				//p2_deg=arc.to_degree;
				
				if(arc.flip==false)
				draw_arc(path_pen,center.x,center.y,arc.r,p1_deg,p2_deg,1);
				else
				draw_arc(path_pen,center.x,center.y,arc.r,p2_deg,p1_deg,1);
				
			}else if(point.isRect){
				
				//draw the rect here
				rect2=getRect2(point);
				dis=rect2.distance;
				h=rect2.height;
				
				corner=getCorner(point);
							
				//here is the 3 points
				center=data[corner[0]];
				p1=data[corner[1]];
				p2=data[corner[2]];
				
				dx1=Math.abs(p1.x-p2.x);
				dy1=Math.abs(p1.y-p2.y);
				
				var l:Number;
				
				if(dx1<dy1){
				
					p1_deg=getDegree(center,p1);
					p2_deg=getDegree(center,p2);
				
					p2_rad=(p2_deg)*Math.PI/180;
					h2=h/Math.sin(360-p2_deg);
					deg3=(getDegree(p2,p1)-90)*Math.PI/180;
				
					l=h/Math.cos(deg3);
					
					p1_adj=adjustPoint(center,p1_deg,l/2);
					p2_adj=adjustPoint(center,p2_deg,l/2);
							
					//draw rect lines
					//var dx:Number=Math.abs(p1_adj.x-p2_adj.x);
					//var dy:Number=Math.abs(p1_adj.y-p2_adj.y);
				
					path_pen.moveTo(p1_adj.x,p1_adj.y);
					path_pen.lineTo(p1_adj.x+dis,p1_adj.y);
					path_pen.lineTo(p1_adj.x+dis,p2_adj.y);
					path_pen.lineTo(p2_adj.x,p2_adj.y);
				}else{
					
					p1_deg=getDegree(center,p1);
					p2_deg=getDegree(center,p2);
					
					l=h;
					
					p1_adj=adjustPoint(center,p1_deg,l/2);
					p2_adj=adjustPoint(center,p2_deg,l/2);
					
					path_pen.moveTo(p1_adj.x,p1_adj.y);
					path_pen.lineTo(p1_adj.x,p1_adj.y+dis);
					path_pen.lineTo(p2_adj.x,p1_adj.y+dis);
					path_pen.lineTo(p2_adj.x,p2_adj.y);
					
				}
				
			}else if(point.isHinge){
				//draw the hinge
				
				hinge=getHinge(point);
				dis=hinge.distance;
				h=hinge.height;
				r=hinge.r;
				corner=getCorner(point);
				
				center=data[corner[0]];
				p1=data[corner[1]];
				p2=data[corner[2]];
				
				dx1=Math.abs(p1.x-p2.x);
				dy1=Math.abs(p1.y-p2.y);
				
				var point_arr:Array;
				var point_arr2:Array;
				var from1:Object;
				var to1:Object;
				var from2:Object;
				var to2:Object;
				
				
				if(dx1>dy1){
					
					//here are vertical hinger
					
					p1_deg=getDegree(center,p1);
					p2_deg=getDegree(center,p2);
					
					l=h;
					
					
					p1_adj=adjustPoint(center,p1_deg,l/2);
					p2_adj=adjustPoint(center,p2_deg,l/2);
					
					//draw rect lines
					//var dx:Number=Math.abs(p1_adj.x-p2_adj.x);
					//var dy:Number=Math.abs(p1_adj.y-p2_adj.y);
					
					
					path_pen.moveTo(p1_adj.x,p1_adj.y);
					
					
					//here draw ear of hinger
					if(p1_adj.x>p2_adj.x){
						if(hinge.distance>0){
							path_pen.lineTo(p1_adj.x,p1_adj.y+dis-r);
							point_arr=draw_arc(path_pen,p1_adj.x,p1_adj.y+dis,hinge.r,-90,180,1);
						}else{
							path_pen.lineTo(p1_adj.x,p1_adj.y+dis+r);
							point_arr=draw_arc(path_pen,p1_adj.x,p1_adj.y+dis,hinge.r,-180,90,1);
						}
					}else{
						if(hinge.distance>0){
							point_arr=draw_arc(path_pen,p1_adj.x,p1_adj.y+dis,hinge.r,0,270,1);
						}else{
							point_arr=draw_arc(path_pen,p1_adj.x,p1_adj.y+dis,hinge.r,90,360,1);
						}
					}
					from1=point_arr[0];
					to1=point_arr[1];
					path_pen.moveTo(p2_adj.x,p1_adj.y+dis-hinge.r);
					
					if(p1_adj.x>p2_adj.x){
						if(hinge.distance>0){
							point_arr2=draw_arc(path_pen,p2_adj.x,p1_adj.y+dis,hinge.r,0,270,1);
						}else{
							point_arr2=draw_arc(path_pen,p2_adj.x,p1_adj.y+dis,hinge.r,90,360,1);
						}
					}else{
						if(hinge.distance>0){
							point_arr2=draw_arc2(path_pen,p2_adj.x,p1_adj.y+dis,hinge.r,-90,180,1);
						}else{
							point_arr2=draw_arc2(path_pen,p2_adj.x,p1_adj.y+dis,hinge.r,-180,90,1);
						}
					}
					from2=point_arr2[0];
					to2=point_arr2[1];
					if(p1_adj.x>p2_adj.x){
						if(hinge.distance>0){
							path_pen.moveTo(to1.x,to2.y+hinge.r);
							path_pen.lineTo(from2.x,from2.y);
							path_pen.moveTo(to2.x,to2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}else{
							path_pen.moveTo(from1.x,from1.y);
							path_pen.lineTo(to2.x,to2.y);
							path_pen.moveTo(from2.x,from2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}
					}else{
						if(hinge.distance>0){
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(to1.x,to1.y);
							path_pen.moveTo(from1.x,from1.y);
							path_pen.lineTo(to2.x,to2.y);
							path_pen.moveTo(from2.x,from2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}else{
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(from1.x,from1.y);
							path_pen.moveTo(to1.x,to1.y);
							path_pen.lineTo(from2.x,from2.y);
							path_pen.moveTo(to2.x,to2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}
					}
				}else{
					//here are horizontal hinger
					
					p1_deg=getDegree(center,p1);
					p2_deg=getDegree(center,p2);
					
					l=h;
					
					
					p1_adj=adjustPoint(center,p1_deg,l/2);
					p2_adj=adjustPoint(center,p2_deg,l/2);
					
					//draw rect lines
					//var dx:Number=Math.abs(p1_adj.x-p2_adj.x);
					//var dy:Number=Math.abs(p1_adj.y-p2_adj.y);
				
					path_pen.moveTo(p1_adj.x,p1_adj.y);
					
					
					//here draw ear of hinger
					if(p1_adj.y<p2_adj.y){
						if(hinge.distance>0){
						//	path_pen.lineTo(p1_adj.x+dis-r,p1_adj.y);
							point_arr=draw_arc(path_pen,p1_adj.x+dis,p1_adj.y,hinge.r,-180,90,1);
						}else{
						//	path_pen.lineTo(p1_adj.x+dis+r,p1_adj.y);
							point_arr=draw_arc(path_pen,p1_adj.x+dis,p1_adj.y,hinge.r,90,360,1);
						}
					}else{
						if(hinge.distance>0){
							point_arr=draw_arc(path_pen,p1_adj.x+dis,p1_adj.y,hinge.r,-90,180,1);
						}else{
							point_arr=draw_arc(path_pen,p1_adj.x+dis,p1_adj.y,hinge.r,0,270,1);
						}
					}
					from1=point_arr[0];
					to1=point_arr[1];
					//path_pen.moveTo(p2_adj.x+dis-hinge.r,p1_adj.y);
					
					if(p1_adj.y>p2_adj.y){
						if(hinge.distance>0){
							point_arr2=draw_arc(path_pen,p1_adj.x+dis,p2_adj.y,hinge.r,-180,90,1);
						}else{
							point_arr2=draw_arc(path_pen,p1_adj.x+dis,p2_adj.y,hinge.r,90,360,1);
						}
					}else{
						if(hinge.distance>0){
							point_arr2=draw_arc2(path_pen,p1_adj.x+dis,p2_adj.y,hinge.r,-90,180,1);
						}else{
							point_arr2=draw_arc2(path_pen,p1_adj.x+dis,p2_adj.y,hinge.r,0,270,1);
						}
					}
					from2=point_arr2[0];
					to2=point_arr2[1];
					
					if(p1_adj.y>p2_adj.y){
						if(hinge.distance>0){
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(to1.x,to1.y);
							path_pen.moveTo(to2.x,to2.y);
							path_pen.lineTo(from1.x,from1.y);
							path_pen.moveTo(from2.x,from2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}else{
							
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(from1.x,from1.y);
							
							path_pen.moveTo(to1.x,to1.y);
							path_pen.lineTo(from2.x,from2.y);

							path_pen.moveTo(to2.x,to2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}
					}else{
						if(hinge.distance>0){
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(from1.x,from1.y);
							path_pen.moveTo(to1.x,to1.y);
							path_pen.lineTo(from2.x,from2.y);
							path_pen.moveTo(to2.x,to2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}else{
							path_pen.moveTo(p1_adj.x,p1_adj.y);
							path_pen.lineTo(to1.x,to1.y);
							path_pen.moveTo(from1.x,from1.y);
							path_pen.lineTo(to2.x,to2.y);
							path_pen.moveTo(from2.x,from2.y);
							path_pen.lineTo(p2_adj.x,p2_adj.y);
						}
					}
					
				}
			}
		}
		
		//draw holes
		var hole:Hole;
		itr=new Iterator(holes.toArray());
		var hole_point:Object;
		while(itr.hasNext()){
			hole=itr.next() as Hole;
			hole_point=data[hole.point];
			path_pen.moveTo(hole_point.x,hole_point.y);
			path_pen.drawCircle(hole_point.x,hole_point.y,hole.r);
		}
		
		//fill meshs
		//create bitmap data of path_mc
			
		while(mesh_mc.numChildren>0){
			mesh_mc.removeChildAt(0);
		}
		itr=new Iterator(colors.toArray());
		var colorObj:Object;
		var rect:Rectangle = path_mc.getBounds(this);
		
		while(itr.hasNext()){
			colorObj=itr.next();
			var bitmapData:BitmapData=new BitmapData(path_mc.width,path_mc.height,true,0x00000000);
			var m:Matrix=new Matrix();
			m.tx = -rect.x;
			m.ty = -rect.y;
			var cp:Object=data[colorObj.point];
			bitmapData.draw(path_mc,m);
			
			bitmapData.floodFill(cp.x-rect.x,cp.y-rect.y,0xFFFFFF00);
			//threshold to remove the black line
			var p3:flash.geom.Point=new flash.geom.Point(0,0);
			bitmapData.threshold(bitmapData,new Rectangle(0,0,rect.width,rect.height),p3,"<",0xFFFFFF00,0x00000000);
			
			//var rect2:Rectangle=new Rectangle(0,0,path_mc.width,path_mc.height);
			//var p:flash.geom.Point=new flash.geom.Point(0,0);
		
			var bm:Bitmap=new Bitmap(bitmapData);
			setMesh(bm,rect);
		}
		
		//draw rulers
		itr=new Iterator(rulers.toArray());
		var ruler:Ruler;
		var ruler_from:Object;
		var ruler_to:Object;
		var arrow_mc:MovieClip;
		var arrow_head_deg:Number;
		var arrow_tail_deg:Number;
		var arrow_text:TextField;
		var center_x:Number;
		var center_y:Number;

		while(itr.hasNext()){
			ruler=itr.next() as Ruler;
			ruler_from=data[ruler.from];
			ruler_to=data[ruler.to];
			path_pen.moveTo(ruler_from.x,ruler_from.y);
			path_pen.lineTo(ruler_to.x,ruler_to.y);

			//put arrow to head of line
			arrow_mc=new Arrow_mc();

			path_mc.addChild(arrow_mc);
			arrow_mc.x=ruler_from.x;
			arrow_mc.y=ruler_from.y;
			//degree of head:
			arrow_head_deg=getDegree(ruler_from,ruler_to);
			arrow_tail_deg=getDegree(ruler_to,ruler_from);

			arrow_mc.rotation=360-arrow_head_deg;

			//add for tail arrow
			arrow_mc=new Arrow_mc();
			path_mc.addChild(arrow_mc);
			arrow_mc.rotation=360-arrow_tail_deg;
			arrow_mc.x=ruler_to.x;
			arrow_mc.y=ruler_to.y;
			
			//add text for the arrow

			arrow_text=new TextField();
			arrow_text.text=ruler.text||"text";
			arrow_text.autoSize="left";
			arrow_text.background=true;
			arrow_text.backgroundColor=0xffffff;

			center_x=(ruler_to.x+ruler_from.x)/2;
			center_y=ruler_to.y-(ruler_to.y-ruler_from.y)/2;
			arrow_text.x=center_x;
			arrow_text.y=center_y;
			arrow_text.x-=arrow_text.width/2;
			arrow_text.y-=arrow_text.height/2;
			path_mc.addChild(arrow_text);


		}

		//mouse_mc
		renderMouseMC();
		getTool().drawPoints(points,point_pen);
		addChild(panel);
		panel.x=-this.w/2+40;
		panel.y=-this.h/2+panel.height;
	}

	public function getPortionOf(p1:Object,p2:Object,portion:Number):Object{
		
		
		var dx:Number=p2.x-p1.x;
		var dy:Number=p2.y-p1.y;
		
		var center:Object={x:p1.x+dx*portion,y:p1.y+dy*portion};
		
		return center;
	}
	
	public function getXML():XML{
		var itr:Iterator;
		var coll:Collection;
		//for loop with array string key
		
		var xml:XML= 
		<items>
			<Points/>
			<Paths/>
			<Rectangles/>
			<Hinges/>
			<Arcs/>
			<Holes/>
			<ColorFills/>
			<Rulers/>
			<Texts/>
		</items>;
		
		//points
		
		coll=this.points;
		//trace("length:"+coll.getLength());
		itr=new Iterator(coll.toArray());
		var p:Object;
		//trace("itr:"+itr);
		var xml_item:XML;
		while(itr.hasNext()){
			p=itr.next();
			
			xml_item=<PointObj id={p.id} x={p.x} y={p.y}/>;
			if(p.isCorner)xml_item.@isCorner=true;
			if(p.isColor)xml_item.@isColor=true;
			if(p.isControl)xml_item.@isControl=true;
			if(p.isHole)xml_item.@isHole=true;
			if(p.isArc)xml_item.@isArc=true;
			if(p.isRect)xml_item.@isRect=true;
			if(p.isHinge)xml_item.@isHinge=true;
			
			xml.Points.appendChild(xml_item);
		}
		
		coll=paths;
		itr=new Iterator(coll.toArray());
		
		return xml;
		
		
	}
	
	public function getPortionNumber(p1:Object,p2:Object,center:Object):Number{
		var num:Number;
		
		var dx:Number=p2.x-p1.x;
		var dy:Number=p2.y-p1.y;
		
		if(Math.abs(dx)>Math.abs(dy)){
			num=(center.x-p1.x)/dx;
		}else{
			num=(center.y-p1.y)/dy;
		}
		
		return num;
	}
	
	//p3 is the target point
	public function getPortion(p1:Object,p2:Object,p3:Object):Number{
		//var p:Object=getCloestPointOnTwoPoints(p1,p2,p3);
		var dx:Number=p2.x-p1.x;
		var dy:Number=p2.y-p1.y;
		var portion:Number;
		
		if(dx>dy){
			portion=(p1.x+p2.x)/p3.x;
		}else{
			portion=(p1.y+p2.y)/p3.y;
		}

		return portion;
	}
	
	public function clearSamePath():void{
		var itr:Iterator=new Iterator(paths.toArray());
		var itr2:Iterator;
		var path:Path;
		var path2:Path;
		
		while(itr.hasNext()){
			path=itr.next() as Path;
			itr2=new Iterator(paths.toArray());
			while(itr2.hasNext()){
				path2=itr2.next() as Path;
				if(path!=path2 && identical(path,path2)){
					removePath(path);
				}
			}
		}
	}
	
	public function identical(path1:Path,path2:Path):Boolean{
		if(path1.identical(path2)){
			return true;
		}
		return false;
	}
	
	public function getHinge(point:Object):Hinge{
		var hinges:Collection=hinges;
		var itr:Iterator=new Iterator(hinges.toArray());
		var item:Hinge;
		while(itr.hasNext()){
			item=itr.next() as Hinge;
			
			if(item.point==point.id){
				return item;
			}
		}
		return null;
		
	}

	public function getText(point:Object):Text{
		var texts:Collection=texts;
		var itr:Iterator=new Iterator(texts.toArray());
		var item:Text;

		while(itr.hasNext()){
			item=itr.next() as Text;
			if(item.point==point.id){
				return item;
			}
		}
		return null;
	}
	
	public function getHole(point:Object):Hole{
		var holes:Collection=holes;
		var itr:Iterator=new Iterator(holes.toArray());
		var item:Hole;
		while(itr.hasNext()){
			item=itr.next() as Hole;
			if(item.point==point.id){
				return item;
			}
		}
		return null;
	}
	
	public function getRect2(point:Object):Rect{
		var rects:Collection=rects;
		var itr:Iterator=new Iterator(rects.toArray());
		var item:Rect;
		while(itr.hasNext()){
			item=itr.next() as Rect;
			if(item.point==point.id){
				return item;
			}
		}
		return null;
		
	}
	public function getArc(point:Object):Arc{
		var arcs:Collection=arcs;
		var itr:Iterator=new Iterator(arcs.toArray());
		var item:Arc;
		while(itr.hasNext()){
			item=itr.next() as Arc;
			if(item.point==point.id){
				
				return item;
			}
		}
		return null;
	}
	
	public function setMesh(bm:Bitmap,rect:Rectangle):void{
	
		
		//use the mesh to be mask of the bitmap shape and addchild to mesh_mc
		var mc:MovieClip=new MovieClip();
		mc.cacheAsBitmap=true;
		bm.cacheAsBitmap=true;
		
		var w:Number=rect.width;
		var h:Number=rect.height;
		var g:Graphics=mc.graphics;
		
	
		g.lineStyle(1,0x000000,1);
		g.beginBitmapFill(new CutOut,null,true,false);
		g.drawRect(0,0,w,h);
		g.endFill();
		
		mc.mask=bm;
		
		bm.x=rect.x;
		bm.y=rect.y;
		mc.x=rect.x;
		mc.y=rect.y;
		
		mesh_mc.addChild(bm);
		mesh_mc.addChild(mc);
		
	}
	
	
	public function adjustPoint(pos:Object,degree:Number,r:Number=20):Object{
		var rad:Number=degree*Math.PI/180;
		var tx:Number;
		var ty:Number;
		
		tx=pos.x+r*Math.cos(rad);
		ty=pos.y-r*Math.sin(rad);
		
		return {x:tx,y:ty};
	}
	
	
	public function draw_arc(pen:Graphics,center_x:Number,center_y:Number,radius:Number,angle_from:Number,angle_to:Number,precision:Number):Array{
		var arr:Array=[];
		if(angle_from>angle_to){
			angle_to+=360;
		}
		
		var angle_diff:Number=angle_to-angle_from;
		var deg_to_rad:Number=0.0174532925;
		var steps:Number=Math.round(angle_diff*precision);
		var angle:Number=angle_from;
		var px:Number=center_x+radius*Math.cos(angle*deg_to_rad);
		var py:Number=center_y+radius*Math.sin(angle*deg_to_rad);
		pen.moveTo(px,py);
		arr[0]={x:px,y:py};
		var tx:Number;
		var ty:Number;
		
		for (var i:int=1; i<=steps; i++) {
			angle=angle_from+angle_diff/steps*i;
			tx=center_x+radius*Math.cos(angle*deg_to_rad);
			ty=center_y+radius*Math.sin(angle*deg_to_rad);
			pen.lineTo(tx,ty);
		}
		arr[1]={x:tx,y:ty};
		return arr;
	}
	
	public function draw_arc2(pen:Graphics,center_x:Number,center_y:Number,radius:Number,angle_from:Number,angle_to:Number,precision:Number):Array{
		var arr:Array=[];
		if(angle_from>angle_to){
			angle_to+=360;
		}
		
		var angle_diff:Number=angle_to-angle_from;
		var deg_to_rad:Number=0.0174532925;
		var steps:Number=Math.round(angle_diff*precision);
		var angle:Number=angle_from;
		var px:Number=center_x+radius*Math.cos(angle*deg_to_rad);
		var py:Number=center_y+radius*Math.sin(angle*deg_to_rad);
		pen.moveTo(px,py);
		arr[0]={x:px,y:py};
		var tx:Number;
		var ty:Number;

		for (var i:int=1; i<=steps; i++) {
			angle=angle_from+angle_diff/steps*i;
			tx=center_x+radius*Math.cos(angle*deg_to_rad);
			ty=center_y+radius*Math.sin(angle*deg_to_rad);
			pen.lineTo(tx,ty);
		}
		arr[1]={x:tx,y:ty};
		return arr;
	}
	
	function getDegree(p1:Object,p2:Object):Number{
		
		var x1:Number=p1.x;
		var x2:Number=p2.x;
		var y1:Number=p1.y;
		var y2:Number=p2.y;
		
		
		y2 *= -1;
		y1*=-1;
		var angle:Number = Math.atan2(y2 - y1, x2 - x1) * (180 / Math.PI);
		return angle < 0 ? angle + 360 : angle;
	}
	
	function getPathDegree(path:Path):Number{
		
		//point from to to
		var p1:Object=data[path.from];
		var p2:Object=data[path.to];
		
		return getDegree(p1,p2);
	}
	
	function getPathsDegree(path1:Path,path2:Path):Number{
		return 0;
	}
	
	public function getTool():Tool{
		if(responsible==null)move_tool.responsible(this);
		return responsible;
	}
	
	//change on settings
	
	public function set compWidth(w:Number):void{
		this.w=w;
		render();
	}
	
	public function get compWidth():Number{
		return w;
	}
	
	public function set compHeight(h:Number):void{
		this.h=h;
		render();
	}
	
	public function get compHeight():Number{
		return h;
	}
	
	//public methods
	
	public function render():void{
		draw();
		drawGrid();
	}
	
	
	//internal use only
	
	private function init(evt:Event):void{

		//parse xml data
		parseData(new XML(evt.target.data));
		//draw
		render();
		trace(getXML());
	}
	
	private function drawGrid():void{
		grid_pen.clear();
		
		if(border){
		//draw border
			grid_pen.lineStyle(1,0x000000,1);
			grid_pen.moveTo(-w/2,-h/2);
			grid_pen.lineTo(w/2,-h/2);
			grid_pen.lineTo(w/2,h/2);
			grid_pen.lineTo(-w/2,h/2);
			grid_pen.lineTo(-w/2,-h/2);
		}
		
		//draw grids
		grid_pen.lineStyle(0.1,0x00ccff,0.5)
		
		//draw vertical line at left side
		for(var lx:Number=0;lx>-w/2;lx-=distance){
			grid_pen.moveTo(lx,-h/2);
			grid_pen.lineTo(lx,h/2);
		}
		
		//draw vertical line at right side
		for(lx=0;lx<w/2;lx+=distance){
			grid_pen.moveTo(lx,-h/2);
			grid_pen.lineTo(lx,h/2);
		}
		
		//draw horizontal line at top
		for(var ly:Number=0;ly>-h/2;ly-=distance){
			grid_pen.moveTo(-w/2,ly);
			grid_pen.lineTo(w/2,ly);
		}
		
		//draw horizontal line at bottom
		for(ly=0;ly<h/2;ly+=distance){
			grid_pen.moveTo(-w/2,ly);
			grid_pen.lineTo(w/2,ly);
		}
		
	}
	
	private function getInstanceOf(className:String):*{
		var classRef:Class=getDefinitionByName(className) as Class;
		return new classRef();
	}
	
	public function get hinges():Hinges{
		return items["Hinges"];
	}
	
	public function get arcs():Arcs{
		return items["Arcs"];
	}
	public function get holes():Holes{
		return items["Holes"];
	}
	
	public function get colors():ColorFills{
		return items["ColorFills"];
	}
	
	public function get paths():Paths{
		return items["Paths"];
	}
	
	public function get points():Points{
		return items["Points"];
	}
	
	public function get rects():Rectangles{
		return items["Rectangles"];
	}

	public function get texts():Texts{
		return items["Texts"];
	}
	
	public function addText(p:Object,select:Boolean=false):void{
		var point:Object=new PointObj();
		point.x=p.x;
		point.y=p.y;

		point.isText=true;
		point.canvas=this;
		point.id=getNewId();
		data[point.id]=point;
		points.addItem(point);

		var txt:Text=new Text();
		txt.id=getNewId();
		txt.canvas=this;
		data[point.id]=point;
		
		txt.point=point.id;
		texts.addItem(txt);

		if(select){
			addItemToSelection(point);
		}
	}

	//param p included x,y,r
	public function addHole(p:Object):void{
		//add point to the points first
		var point:Object=new PointObj();
		point.x=p.x;
		point.y=p.y;
		
		point.isHole=true;
		point.canvas=this;
		point.id=getNewId();
		data[point.id]=point;
		points.addItem(point);
		//add hole to holes collection
		var hole:Hole=new Hole();
		hole.id=getNewId();
		hole.canvas=this;
		data[hole.id]=hole;
		
		hole.point=point.id;
		hole.r=p.r;
		holes.addItem(hole);
		
	}
	
	public function addHinge(point:Object):void{
		point.isHinge=true;
		
		var hinge:Hinge=new Hinge();
		hinge.id=getNewId();
		hinge.canvas=this;
		data[hinge.id]=hinge;
		
		hinge.point=point.id;
		hinge.distance=40;
		hinge.height=30;
		hinge.portion=0.5;
		hinge.r=8;
		
		hinges.addItem(hinge);
	}
	
	public function addRect(point:Object):void{
		point.isRect=true;
		
		var rect:Rect=new Rect();
		rect.id=getNewId();
		rect.canvas=this;
		data[rect.id]=rect;
		
		rect.point=point.id;
		rect.distance=20;
		rect.height=25;
		rect.portion=0.5;
		
		rects.addItem(rect);
		trace("add rects");
	}
	
	//add arc with point that aldy added
	public function addArc(point:Object):void{
		point.isArc=true;
		
		var arc:Arc=new Arc();
		arc.id=getNewId();
		arc.canvas=this;
		data[arc.id]=arc;
		
		arc.point=point.id;
		arc.r=20;
		arcs.addItem(arc);
		
	}
	
	public function addNewPointAtLine(x:Number,y:Number,line:Object):Object{
		var point:Object=new PointObj();
		point.x=x;
		point.y=y;
		point.canvas=this;
		point.id=getNewId();
		
		line.splitPath(addPoint);
		
		data[point.id]=point;
		points.addItem(point);
		return point;
		
	}
	
	public function addPoint(p:Object):void{
		if(points.contains(p))return;
		trace("x:"+p.x+",y:"+p.y);
		data[p.id]=p;
		p.canvas=this;
		points.addItem(p);
		
	}
	
	public function addColor(p:Object):void{
		if(points.contains(p))return;
		
		data[p.id]=p;
		p.canvas=this;
		
		points.addItem(p);
		var c:ColorFill=new ColorFill();
		c.point=p.id;
		c.id=getNewId();
		
		p.isColor=true;
		c.color="CutOut";
		data[c.id]=c;
		
		colors.addItem(c);
	}
	
	public function removeHolePoint(p:Object):void{
		trace("remove hole point");
		var itr:Iterator=new Iterator(holes.toArray());
		var item:Hole;
		while(itr.hasNext()){
			item=itr.next() as Hole;
			if(item!=null && item.point==p.id){
				delete data[item.id];
				holes.removeItem(item);
			}
		}
		removePoint(p);
	}
	public function removeColorPoint(p:Object):void{
		trace("remove color point");
		var itr:Iterator=new Iterator(colors.toArray());
		var item:ColorFill;
		while(itr.hasNext()){
			item=itr.next() as ColorFill;
			if(item!=null && item.point==p.id){
				delete data[item.id];
				//item.canvas=null;
				colors.removeItem(item);
			}
		}
		removePoint(p);
	}
	
	public function removePoint(p:Object):void{
		delete data[p.id];
		p.canvas=null;
		points.removeItem(p);
		
		if(p.isText){
			removeText(p);
		}
	}

	public function removeText(p:Object):void{
		var tf:TextField=text_data[p];
		text_mc.removeChild(tf);
	}
	
	public function removePathsWithPoint(p:Object):void{
		var itr:Iterator=new Iterator(paths.toArray());
		var item:Path;
		
		while(itr.hasNext()){
			item=itr.next() as Path;
			if(item.from==p.id || item.to==p.id){
				removePath(item);
			}
		}
	}
	
	public function removePath(p:Path):void{
		trace(p);
		delete data[p.id];
		p.canvas=null;
		paths.removeItem(p);
	}
	
	public function removePointFromPaths(p:Object):void{
		//join 2 paths to 1
		var itr:Iterator=new Iterator(paths.toArray());
		var to_p:Path;
		var from_p:Path;
		
		while(itr.hasNext()){
			var item:Path=itr.next() as Path;
			if(item.contains(p)){
				removePath(item);
			}
		}
		
	}
	
	public function addPath(p:Object):void{
		data[p.id]=p;
		p.canvas=this;
		paths.addItem(p);
	}

	public function addRuler(p:Object):void{
		data[p.id]=p;
		p.canvas=this;
		rulers.addItem(p);
	}
	
	public function get rulers():Rulers{
		return items["Rulers"];
	}
	
	public function getPathWithControlId(id:int):Path{
		var itr:Iterator=new Iterator(paths.toArray());
		while(itr.hasNext()){
			var item:Path=itr.next() as Path;
			if(item.control==id){
				return item;
			}
		}
		return null;
	}
	
	//utils functions
	public function getClosePoint(except:Object=null):Item{
		var itr:Iterator=new Iterator(points.toArray());
		var d:Number=closePointDistance;
		while(itr.hasNext()){
			var p:Item=itr.next() as Item;
			if(pointDistance(p,mousePoint())<d){
				if(p!=except)
				return p;
			}
		}
		return null;
	}
	
	//return 3 points of the corner
	public function getCorner(p:Object):Array{
		// need to loop though path collection, to know which 3 points for the corner point
		var itr:Iterator=new Iterator(paths.toArray());
		var item:Object;
		var result:Array=[p.id];
		while(itr.hasNext()){
			item=itr.next();
			if(item.contains(p)){
				getUniqueArray(result,item.to);
				getUniqueArray(result,item.from);
			}
		}
		
		if(result.length==3){
			//means got 3 points
			return result;			
		}
		return null;
	}
	
	public function getUniqueArray(arr:Array,value:*):Array{
		for(var i:int=0;i<arr.length;i++){
			if(arr[i]==value){
				return arr;
			}
		}
		arr.push(value);
		return arr;
	}
	
	public function getCloestPointOnTwoPoints(p1:Object,p2:Object,target:Object):Object{
		var p1:Object=p1;
		var p2:Object=p2;
		var dx:Number=p2.x-p1.x;
		var dy:Number=p2.y-p1.y;
		var dx2_plus_dy2:Number=p1.x*p1.x+p2.y*p1.y;
		
		var u:Number=((target.x-p1.x)*dx+(target.y-p1.y)*dy)/dx2_plus_dy2;
		if(u<0){
			return p1;
		}else if(u>1){
			return p2;
		}else{
			return {x:p1.x+u*dx,y:p1.y+u*dy};
		}
	}
	
	public function getCloestPointOnPath(point:Object,path:Path):Object{
		
		var p1:Object=data[path.from];
		var p2:Object=data[path.to];
		var dx:Number=path.getDx(data);
		var dy:Number=path.getDy(data);
		var dx2_plus_dy2:Number=path.getDX2_plus_dy2(data);
		
		var u:Number=((point.x-p1.x)*dx+(point.y-p1.y)*dy)/dx2_plus_dy2;
		
		if(u<0){
			return p1;
		}else if(u>1){
			return p2;
		}else{
			return {x:p1.x+u*dx,y:p1.y+u*dy};
		}
	}
	
	public function getCloseLine(except:Path=null):Array{
		var lines:Array;
		var dist:Number;
		var results:Array=[];
		var temp:Array=[];
		
		var item:*;
		
		var mp:Object=mousePoint();
		var path_arr:Array=paths.toArray();
		
		for(var i:int=0;i<path_arr.length;i++){
			item=path_arr[i];
			dist=pointLineDistance(mp,item);
			if(dist<closeLineDistance && item.control==-1){
				if(item!=except)
				temp.push({dist:dist,item:item});
			}
		}
		
		temp.sortOn("dist");
		
		for(var j:int=0;j<temp.length;j++){
			results.push(temp[j].item);
		}
		
		return results;
	}
	
	public function isClose(path:Path):Boolean{
		var dist:Number=pointLineDistance(mousePoint(),path);
		if(dist<closeLineDistance){
			return true;
		}
		return false;
		
	}
	
	public function pointLineDistance(point:Object,path:Path):Number{
		var p1:Object=data[path.from];
		var p2:Object=data[path.to];
		var dx:Number=path.getDx(data);
		var dy:Number=path.getDy(data);
		var dx2_plus_dy2:Number=path.getDX2_plus_dy2(data);
		
		var u:Number=((point.x-p1.x)*dx+(point.y-p1.y)*dy)/dx2_plus_dy2;
		if(u<0){
			return pointDistance(point,p1);
		}else if(u>1){
			return pointDistance(point,p2);
		}else{
			return pointDistance(point,{x:p1.x+u*dx,y:p1.y+u*dy});
		}
		
	}
}

}

